package net.haier.fashion.trend.report.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.http.HttpMethod;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.security.Principal;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

@Slf4j
public class TraceUtil {
    private static final Set<Include> DEFAULT_INCLUDES;

    public TraceUtil() {
    }

    public static Map<String, Object> getTrace(HttpServletRequest request) {
        Map<String, Object> trace = getTraceMap(request);
        String requestBody = getRequestBody(request);
        if (Strings.isNotEmpty(requestBody)) {
            trace.put("body", requestBody);
        }

        return trace;
    }

    public static String getRequestBody(HttpServletRequest request) {
        ContentCachingRequestWrapper wrapper;
        if (!(request instanceof ContentCachingRequestWrapper)) {
            wrapper = new ContentCachingRequestWrapper(request);
        } else {
            wrapper = (ContentCachingRequestWrapper)request;
        }

        return getRequestBody(wrapper);
    }

    public static String getRequestBody(ContentCachingRequestWrapper request) {
        String body = null;
        if (!request.getMethod().equals(HttpMethod.GET.name())) {
            try {
                body = new String(request.getContentAsByteArray(), request.getCharacterEncoding());
            } catch (Exception var3) {
                Exception e = var3;
                log.error("读取请求体异常：", e);
            }
        }

        return body;
    }

    private static Map<String, Object> getTraceMap(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        Principal userPrincipal = request.getUserPrincipal();
        Map<String, Object> trace = new LinkedHashMap();
        new LinkedHashMap();
        trace.put("traceId", ThreadLocalUtil.get("tcId"));
        trace.put("method", request.getMethod());
        trace.put("path", request.getRequestURI());
        if (isIncluded(TraceUtil.Include.REQUEST_HEADERS)) {
            trace.put("headers", getRequestHeaders(request));
        }

        add(trace, TraceUtil.Include.PATH_INFO, "pathInfo", request.getPathInfo());
        add(trace, TraceUtil.Include.PATH_TRANSLATED, "pathTranslated", request.getPathTranslated());
        add(trace, TraceUtil.Include.CONTEXT_PATH, "contextPath", request.getContextPath());
        add(trace, TraceUtil.Include.USER_PRINCIPAL, "userPrincipal", userPrincipal == null ? null : userPrincipal.getName());
        if (isIncluded(TraceUtil.Include.PARAMETERS)) {
            trace.put("parameters", getParameterMapCopy(request));
        }

        add(trace, TraceUtil.Include.QUERY_STRING, "query", request.getQueryString());
        add(trace, TraceUtil.Include.AUTH_TYPE, "authType", request.getAuthType());
        add(trace, TraceUtil.Include.REMOTE_ADDRESS, "remoteAddress", request.getRemoteAddr());
        add(trace, TraceUtil.Include.SESSION_ID, "sessionId", session == null ? null : session.getId());
        add(trace, TraceUtil.Include.REMOTE_USER, "remoteUser", request.getRemoteUser());
        return trace;
    }

    private static boolean isIncluded(Include include) {
        return DEFAULT_INCLUDES.contains(include);
    }

    public static Map<String, Object> getRequestHeaders(HttpServletRequest request) {
        Map<String, Object> map = new HashMap();
        Enumeration<String> headerNames = request.getHeaderNames();

        while(headerNames.hasMoreElements()) {
            String key = (String)headerNames.nextElement();
            map.put(key, request.getHeader(key));
        }

        return map;
    }

    private static void add(Map<String, Object> trace, Include include, String name, Object value) {
        if (isIncluded(include) && value != null) {
            trace.put(name, value);
        }

    }

    private static Map<String, String[]> getParameterMapCopy(HttpServletRequest request) {
        return new LinkedHashMap(request.getParameterMap());
    }

    static {
        Set<Include> defaultIncludes = new LinkedHashSet();
        Arrays.stream(TraceUtil.Include.values()).forEach((x) -> {
            defaultIncludes.add(x);
        });
        DEFAULT_INCLUDES = Collections.unmodifiableSet(defaultIncludes);
    }

    public static enum Include {
        REQUEST_HEADERS,
        RESPONSE_HEADERS,
        COOKIES,
        AUTHORIZATION_HEADER,
        ERRORS,
        PATH_INFO,
        PATH_TRANSLATED,
        CONTEXT_PATH,
        USER_PRINCIPAL,
        PARAMETERS,
        QUERY_STRING,
        AUTH_TYPE,
        REMOTE_ADDRESS,
        SESSION_ID,
        REMOTE_USER,
        TIME_TAKEN;

        private Include() {
        }
    }
}
